// ======================================================================
// Copyright (C) 2013 Hell-Prototypes. / www.hellprototypes.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// ======================================================================
#include <QApplication>
#include "hell_vo.h"
#include "ui_hell_vo.h"
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Hell_VO w;
    w.show();

    return a.exec();
}
/*****************************************************************************/

Hell_VO::Hell_VO(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Hell_VO)
{
    m_circular_buffer_ctrl.p_buffer = NULL;

    ui->setupUi(this);
    ui_init();

    m_USB_Thread = new USB_Thread(this);
    connect(m_USB_Thread, SIGNAL(rle_data_ready(int)), SLOT(process_rle_data(int)));
    connect(m_USB_Thread, SIGNAL(usb_error(int)), SLOT(process_usb_error(int)));
    connect(m_USB_Thread, SIGNAL(note_message(QString)), SLOT(note_message(QString)));
}

Hell_VO::~Hell_VO()
{
    if(m_USB_Thread->isRunning()) {
        m_USB_Thread->stop_data_read();
        m_USB_Thread->wait(3*1000);
    }
    m_USB_Thread->disconnect_usb();

    delete m_USB_Thread;

    if(m_circular_buffer_ctrl.p_buffer != NULL) {
        free(m_circular_buffer_ctrl.p_buffer);
        m_circular_buffer_ctrl.p_buffer = NULL;
    }

    delete ui;
}

void Hell_VO::ui_init()
{
    m_plot_wave_form = new plot_wave_form(this);
    ui->splitter_display->insertWidget(0, m_plot_wave_form);

    QStringList time_base;
    time_base << "20nS" << "50nS" << "100nS" << "200nS" << "500nS" \
              << "1uS" << "2uS" << "5uS" << "10uS" << "20uS" << "50uS" << "100uS" << "200uS" << "500uS" \
              << "1mS" << "2mS" << "5mS" << "10mS" << "20mS" << "50mS" << "100mS" << "200mS" << "500mS";
    for(int i=0; i<time_base.size(); i++) {
        int k;
        QString unit = time_base.at(i).right(2);
        if(unit == "nS")      { k = 1; }
        else if(unit == "uS") { k = 1000; }
        else if(unit == "mS") { k = 1000 * 1000; }
        else { break; }
        m_x_axis_time_list << (double)(time_base.at(i).left(time_base.at(i).size() - 2).toInt()) * k * 10;
    }

    ui->cb_time_base->addItems(time_base);
    ui->cb_time_base->setCurrentIndex(time_base.indexOf("20mS"));
}

void Hell_VO::note_message(QString msg)
{
    ui->pte_disp_msg->appendPlainText(msg);
}

void Hell_VO::on_pb_usb_connect_clicked(bool checked)
{
    if(checked) {
        if(!m_USB_Thread->connect_usb()) {
            ui->pb_usb_connect->setChecked(false);
        } else {
            ui->pb_usb_connect->setText("Running");
            m_USB_Thread->set_sampling_divider(0x01);
            m_USB_Thread->start();
            m_plot_wave_form->start_plot();
        }
    } else {
        m_USB_Thread->disconnect_usb();
        ui->pb_usb_connect->setText("IDLE");
        ui->pb_usb_connect->setChecked(false);
        m_plot_wave_form->stop_plot();
    }
}

void Hell_VO::process_usb_error(int err_code)
{
    if(m_USB_Thread->isRunning()) {
        m_USB_Thread->stop_data_read();
        m_USB_Thread->wait();
    }
    m_plot_wave_form->stop_plot();
    on_pb_usb_connect_clicked(false);
    note_message(QString("USB error: %1").arg(err_code));
}

int Hell_VO::get_sampling_interval(QString rate)//return unit: ns
{
    if(rate.isEmpty()) {
        return -1;
    }

    int num = rate.left(rate.size() - 3).toInt();

    if(num > 0) {
        return 20 * 50 / num;
    } else {
        return num;
    }
}

void Hell_VO::on_cb_time_base_currentIndexChanged(int index)
{
    //m_h_axis_time_list
    int sampling_interval = get_sampling_interval(ui->cb_sampling_rate->currentText());
    if(sampling_interval <= 0) {
        note_message("get sampling interval fail");
        return;
    }

    m_x_axis_sample_number = m_x_axis_time_list.at(index) / (double)sampling_interval;
//    if(m_x_axis_sample_number <= 500000) {//100ms
//        m_circular_buffer_ctrl.buffer_length = 2 * m_x_axis_sample_number;
//    } else {
//        m_circular_buffer_ctrl.buffer_length = m_x_axis_sample_number;
//    }
    m_circular_buffer_ctrl.size = m_x_axis_sample_number;

    if(m_circular_buffer_ctrl.p_buffer != NULL) {
        delete [] m_circular_buffer_ctrl.p_buffer;
        m_circular_buffer_ctrl.p_buffer = NULL;
    }

    m_circular_buffer_ctrl.p_buffer = new uchar [m_circular_buffer_ctrl.size];
    if(m_circular_buffer_ctrl.p_buffer == NULL) {
        if(ui->pb_usb_connect->isChecked()) {
            on_pb_usb_connect_clicked(false);
        }
        ui->pb_usb_connect->setEnabled(false);
        note_message(QString("Error: Fail to alloc memory, size = %1").arg(m_circular_buffer_ctrl.size));
    } else {
        ui->pb_usb_connect->setEnabled(true);
        note_message(QString("Memory alloc ok, size = %1").arg(m_circular_buffer_ctrl.size));
        m_circular_buffer_ctrl.start = m_circular_buffer_ctrl.size - 1;
        m_circular_buffer_ctrl.data_length = 0;

    }

    note_message(QString("disp_sample_number = %1").arg(m_x_axis_sample_number));
    m_plot_wave_form->set_x_axis_sample_number(m_x_axis_sample_number);
}

void Hell_VO::on_cb_sampling_rate_currentIndexChanged(int index)
{
    index = index;

    on_cb_time_base_currentIndexChanged(ui->cb_time_base->currentIndex());
}

void Hell_VO::process_rle_data(int data_len)
{
    //m_sys_clock.restart();
    m_USB_Thread->fifo_take(m_rle_data, data_len);
    //qDebug("1 m_sys_clock.elapsed() = %f", m_sys_clock.elapsed());
    //m_sys_clock.restart();
    t_circular_buffer *t = &m_circular_buffer_ctrl;

    for (int i=0; i<data_len; i+=2) {
        for (int j=0; j<((int)((uchar)m_rle_data[i+1]) + 1); j++) {
            if(t->start == t->size - 1) {
                t->start = 0;
            } else {
                t->start++;
            }
            t->p_buffer[t->start] = (uchar)m_rle_data[i];
            if(t->data_length < t->size) { t->data_length++; }
        }
    }
    //qDebug("2 m_sys_clock.elapsed() = %f", m_sys_clock.elapsed());
    //m_sys_clock.restart();
    m_plot_wave_form->new_data_arise(t);
    //qDebug("3 m_sys_clock.elapsed() = %f", m_sys_clock.elapsed());
}
